package frsf.cidisi.exercise.modelo.search;

import java.util.List;

import frsf.cidisi.exercise.modelo.util.Coordenada;
import frsf.cidisi.exercise.modelo.util.Laberinto;
import frsf.cidisi.exercise.modelo.util.Orientacion;
import frsf.cidisi.exercise.modelo.util.Salida;
import frsf.cidisi.faia.agent.Perception;
import frsf.cidisi.faia.agent.search.SearchBasedAgentState;

/**
 * Represent the internal state of the Agent.
 */
public class AgenteEstado extends SearchBasedAgentState {
	
    private Coordenada posAgente;
    private Orientacion orientacion;    
    private List<Coordenada> entradas;
    private List<Salida> salida;
    private List<Coordenada> posLlaves;
    private boolean tieneLlave;
    private Laberinto laberinto;
    private Coordenada entradaAgente;
	

    public AgenteEstado(Coordenada posAgente, Orientacion orientacion,
			List<Coordenada> entradas, List<Salida> salida, List<Coordenada> posLlaves,
			boolean tieneLlave, Laberinto laberinto, Coordenada entradaAgente) {
		super();
		this.posAgente = posAgente;
		this.orientacion = orientacion;
		this.entradas = entradas;
		this.salida = salida;
		this.posLlaves = posLlaves;
		this.tieneLlave = tieneLlave;
		this.laberinto = laberinto;
		this.entradaAgente = entradaAgente;
	}

	public AgenteEstado() {
    
    	//TODO: Complete Method
		
        this.initState();
    }

    /**
     * This method clones the state of the agent. It's used in the search
     * process, when creating the search tree.
     */
    @Override
    public SearchBasedAgentState clone() {
        
    	AgenteEstado agState = new AgenteEstado(this.posAgente, this.orientacion, this.entradas, 
    			this.salida, this.posLlaves, this.tieneLlave, this.laberinto, this.entradaAgente);
		
        return agState;
    }

    /**
     * This method is used to update the Agent State when a Perception is
     * received by the Simulator.
     */
    @Override
    public void updateState(Perception p) {
    	AgentePerception percepcion = (AgentePerception) p;
    	
    	this.setLaberinto(percepcion.getLaberinto());
    	this.setentrada(percepcion.getListaEntradas());
    	this.setSalida(percepcion.getListaSalidas());
    	this.setPosLlaves(percepcion.getListaLlaves());
    	
    	if(entradaAgente == null && entradas != null)
    		entradaAgente = getentrada().get(0);
        
    }

    /**
     * This method is optional, and sets the initial state of the agent.
     */
    @Override
    public void initState() {
        
		posAgente = new Coordenada(0,0);
		entradaAgente = new Coordenada(0,0);
		orientacion = new Orientacion(3);
		entradas = null;
		salida = null;
		posLlaves = null;
		tieneLlave = false;
		laberinto = new Laberinto(10,10);
	
    }

    /**
     * This method returns the String representation of the agent state.
     */
    @Override
	public String toString() {
		//String str = "";

		// TODO: Complete Method
		// pos, or, tieneLLave, accion
		return "Posicion: " + this.posAgente.toString() + " - Orientacion: " + this.orientacion.getValue() 
    		+ " Tiene llave: " + (this.tieneLlave? "Si" : "No");
    	
	}

    /**
     * This method is used in the search process to verify if the node already
     * exists in the actual search.
     */
    @Override
    public boolean equals(Object obj) {
    	if (!(obj instanceof AgenteEstado))
            return false;
    	
    	//Laberinto objLaberinto = ((AgenteEstado)obj).getLaberinto();
    	//Coordenada objPosicion = ((AgenteEstado)obj).getPosAgente();
    	//boolean objTieneLlave = ((AgenteEstado)obj).getTieneLlave();
    	//Orientacion objOrientacion = ((AgenteEstado)obj).getOrientacion();
    	
    	if(! this.posAgente.equals(((AgenteEstado)obj).getPosAgente()))
    		return false;
    	else if(this.orientacion.getValue() != ((AgenteEstado)obj).getOrientacion().getValue())
    		return false;
    	else if(this.tieneLlave != ((AgenteEstado)obj).getTieneLlave())
    		return false;
    	
    	/*if(!(this.laberinto.equals(((AgenteEstado)obj).getLaberinto())))
    		return false;*/
    	
        return true;
    }

    //TODO: Complete this section with agent-specific methods
    // The following methods are agent-specific:
   	
     public Coordenada getPosAgente(){
        return posAgente;
     }
     public void setposAgente(Coordenada posAgente){
        this.posAgente = posAgente;
     }

     public List<Coordenada> getentrada(){
        return entradas;
     }
     
     public Coordenada getEntradaAgente(){
    	 return this.entradaAgente;
     }
     
     public void setentrada(List<Coordenada> entradas){
        this.entradas = entradas;
     }

     public List<Coordenada> getPosLlaves(){
        return posLlaves;
     }
     public void setPosLlaves(List<Coordenada> posLlaves){
        this.posLlaves = posLlaves;
     }
     public boolean getTieneLlave(){
        return tieneLlave;
     }
     public void setTieneLlave(boolean tieneLlave){
        this.tieneLlave = tieneLlave;
     }
     public Laberinto getLaberinto(){
        return laberinto;
     }
     public void setLaberinto(Laberinto laberinto){
        this.laberinto = laberinto;
     }

	public void setSalida(List<Salida> salida) {
		this.salida = salida;
	}

	public List<Salida> getSalida() {
		return salida;
	}

	public void setOrientacion(Orientacion orientacion) {
		this.orientacion = orientacion;
	}

	public Orientacion getOrientacion() {
		return orientacion;
	}
	
	public void addLlave(Coordenada posicion) {
		this.posLlaves.add(posicion);
	}
	
	public void removeLlave(Coordenada posicion) {
		this.posLlaves.remove(posicion);
	}
	
	public void pasarNivel(){
		
	}

	public void setEntradaAgente(Coordenada coordenada) {
		this.entradaAgente = coordenada;		
	}
	
}

